package com.app.baselibrary.delegate
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import com.app.baselibrary.R
import com.app.baselibrary.base.BaseViewModel
import com.app.baselibrary.base.BaseViewModelActivity
import com.app.baselibrary.base.BaseViewModelFragment
import com.app.baselibrary.ktx.getString
import com.app.baselibrary.ktx.runUI
import com.app.baselibrary.view.CustomerLoadingDailog
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import kotlinx.coroutines.CoroutineScope
import java.lang.reflect.ParameterizedType

/**
 *
 */
interface ViewModelComponent<VM: BaseViewModel> {

    /**
     * 绑定activity页面所需组件
     * @param activity [AppCompatActivity]
     */
    fun bindViewModelComponent(activity: AppCompatActivity)

    /**
     * 绑定fragment页面所需组件
     * @param fragment [Fragment]
     */
    fun bindViewModelComponent(fragment: Fragment)

    /**
     * 使用[LiveData]时的扩展方法
     * 返回的观察数据不会为空
     */
    fun <T> LiveData<T>.observerNotNull(action: (T) ->Unit)

    /**
     * 使用[LiveData]时的扩展方法
     * 返回的观察数据可能为空
     */
    fun <T> LiveData<T?>.observerNullable(action: (T?)->Unit)

    /**
     * 显示加载框
     */
    fun showProgress()

    /**
     * 显示加载框
     * @param title 加载框显示的标题
     */
    fun showProgress(title: String)

    /**
     * 隐藏加载框
     */
    fun hideProgress()

    /**
     * 手动结束刷新
     */
    fun finishRefresh(mSmartRefreshLayout: SmartRefreshLayout)

    /**
     * 手动结束加载
     */
    fun finishLoadMore(mSmartRefreshLayout: SmartRefreshLayout)
    /**
     * 获取[BaseViewModel]
     */
    fun requireViewModel(): VM

    /**
     * 获取[ViewModel.viewModelScope]
     */
    fun requireViewModelScope(): CoroutineScope

}

/**
 * 实现了组件代理类
 */
internal class ContextViewModelComponent<VM: BaseViewModel> : ViewModelComponent<VM>,
    DefaultLifecycleObserver {

    private var owner: Any? = null

    private var  dialog: CustomerLoadingDailog?=null

    private var  dialogBuiler: CustomerLoadingDailog.Builder?=null

    private var viewModel: VM? = null

    override fun bindViewModelComponent(activity: AppCompatActivity){
        this.owner = activity
        dialogBuiler=CustomerLoadingDailog.Builder(activity).setCancelOutside(false).setCancelable(false)
        activity.lifecycle.addObserver(this)
        viewModel = bindViewModel(activity)
        initProgressDialog()
    }

    override fun bindViewModelComponent(fragment: Fragment){
        this.owner = fragment
        dialogBuiler=CustomerLoadingDailog.Builder(fragment.requireActivity()).setCancelOutside(false).setCancelable(false)
        fragment.lifecycle.addObserver(this)
        viewModel = bindViewModel(fragment)
        initProgressDialog()
    }


    private fun initProgressDialog(){
        viewModel?.progressLiveData?.observerNotNull{
            val progressInfoBean = it ?: return@observerNotNull
            if (progressInfoBean.show){
                showProgress(progressInfoBean.title)
            }else{
                hideProgress()
            }
        }

    }

    override fun <T> LiveData<T>.observerNotNull(action: (T) -> Unit) {
        requireOwner {
            this.observe(it, Observer { data->
                action.invoke(data)
            })
        }
    }

    override fun <T> LiveData<T?>.observerNullable(action: (T?)->Unit){
        requireOwner {
            this.observe(it, Observer { data->
                action.invoke(data)
            })
        }
    }

    private fun requireOwner(action:(LifecycleOwner)->Unit) {
        if (owner != null){
            if (owner is AppCompatActivity){
                action.invoke(owner as AppCompatActivity)
            }else if (owner is Fragment){
                action.invoke(owner as Fragment)
            }
        }
    }

    /**
     * 获取[BaseViewModel]
     */
    override fun requireViewModel(): VM {
        if (viewModel == null){
            throw IllegalArgumentException("viewModel can not init you should call bind method when ui create")
        }
        return viewModel!!
    }

    override fun requireViewModelScope(): CoroutineScope {
        return requireViewModel().viewModelScope
    }



    override fun showProgress() {
        showProgress(getString(R.string.base_progress_dialog_title))
    }

    override fun finishRefresh(mSmartRefreshLayout: SmartRefreshLayout) {
        runUI(1500){
            mSmartRefreshLayout.finishRefresh()
        }
    }

    override fun finishLoadMore(mSmartRefreshLayout: SmartRefreshLayout) {
        runUI(1500){
            mSmartRefreshLayout.finishLoadMore()
        }
    }

    override fun showProgress(title: String) {
        if (dialog?.isShowing == true){
            dialog?.dismiss()
        }
        dialog=dialogBuiler?.create(title)
        dialog?.show()
    }

    override fun hideProgress() {
        dialog?.dismiss()
    }


    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        dialogBuiler=null
        dialog = null
        this.owner = null
    }


    /**
     * 绑定viewModel
     * @param target activity 或者 fragment
     * @return ViewBinding
     */
    private fun <VM: BaseViewModel>bindViewModel(target: Any): VM {
        if (target !is BaseViewModelActivity<*, *> &&
            target !is BaseViewModelFragment<*, *>
        ){
            throw IllegalArgumentException("target 必须为 BaseActivity 或者 BaseFragment")
        }

        val targetClazz = target.javaClass
        val parameterizedType = targetClazz.genericSuperclass as ParameterizedType
        val viewModelClazz = parameterizedType.actualTypeArguments[1] as Class<*>
        @Suppress("UNCHECKED_CAST")
        return if (target is BaseViewModelFragment<*, *>) {
            ViewModelProvider(target).get(viewModelClazz as Class<VM>)
        }
        else {
            ViewModelProvider(target as BaseViewModelActivity<*, *>)[viewModelClazz as Class<VM>]
        }
    }


}

/**
 * [LifecycleComponent] 代理方法
 * 当前方法用在[AppCompatActivity] [Fragment]
 * eg: class MainActivity : AppCompatActivity(),ViewModelComponent<VM> by lifecycleComponent() {
 *          override fun onCreate(savedInstanceState: Bundle?) {
 *                super.onCreate(savedInstanceState)
 *                bind(this)
 *                setContentView(requireViewBinding().root)
 *         }
 *    }
 * eg: class MainFragment : Fragment(),ViewModelComponent<VM> by lifecycleComponent() {
 *          override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
 *               bind(this)
 *               return requireViewBinding().root
 *        }
 *   }
 */
internal fun <VM: BaseViewModel>viewModelComponent()=
    ContextViewModelComponent<VM>()